#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <string.h>
#include <ctype.h>


char* FileToArray(char* FileName)
{
    if (!FileName) return NULL;
    FILE* source = fopen(FileName, "r");
    if (!source) return NULL;
    long long unsigned Length = (long long unsigned) _filelength(_fileno(source));
    if (Length == 0) return NULL;
    char* result = (char*) calloc(Length + 1, sizeof(char));
    if (!result) return NULL;
    for (int i = 0; i < Length; i++) result[i] = fgetc(source);
    fclose(source);
    return result;
}

typedef enum {EOC = 0, NUMBER = 1, OP = 2, VAR = 3, BR = 4, FUNC = 5, DOT = 6, EOE = 7, IO = 8, COND = 9, CONDOP = 10, CYCLE = 11} TYPE;
typedef enum {SIN = 1, COS = 2} FUNCTION;
typedef enum {SCAN = 1, PRINT = 2} INOUT;
typedef enum {IF = 1, ELSE = 2} CONDOPERATOR;
typedef enum {JE = 1, JNE = 2, JB = 3, JBE = 4, JA = 5, JAE = 6} CONDITION;
typedef enum {FOR = 1, WHILE = 2} CYC;

typedef struct
{
    TYPE type;
    union
    {
        char op;
        int number;
        char var;
        char br;
        FUNCTION func;
        INOUT io;
        CONDITION cond;
        CONDOPERATOR condop;
        CYC cycle;
    };
} token;

token* LexAn(char* Text)
{
    if (!Text) return NULL;
    char* crnt = Text;
    long Length = strlen(Text);
    token* result = (token*) calloc(Length + 1, sizeof(token));
    if (!result) return NULL;

    int i = 0;
    while (*crnt != '\0')
    {

        while (isspace(*crnt)) crnt++;

        if (strncmp("sin", crnt, 3) == 0)
        {
            crnt += 3;
            result[i].type = FUNC;
            result[i].func = SIN;
            i++;
        }

        else if (strncmp("cos", crnt, 3) == 0)
        {
            crnt += 3;
            result[i].type = FUNC;
            result[i].func = COS;
            i++;
        }

        else if(strncmp("print", crnt, 5) == 0)
        {
            crnt += 5;
            result[i].type = IO;
            result[i].io = PRINT;
            i++;
        }

        else if(strncmp("scan", crnt, 4) == 0)
        {
            crnt += 4;
            result[i].type = IO;
            result[i].io = SCAN;
            i++;
        }

        else if(strncmp("==", crnt, 2) == 0)
        {
            crnt += 2;
            result[i].type = COND;
            result[i].cond = JE;
            i++;
        }

        else if(strncmp("!=", crnt, 2) == 0)
        {
            crnt += 2;
            result[i].type = COND;
            result[i].cond = JNE;
            i++;
        }

        else if(strncmp("<=", crnt, 2) == 0)
        {
            crnt += 2;
            result[i].type = COND;
            result[i].cond = JBE;
            i++;
        }

        else if(strncmp(">=", crnt, 2) == 0)
        {
            crnt += 2;
            result[i].type = COND;
            result[i].cond = JAE;
            i++;
        }

        else if(strncmp(">", crnt, 1) == 0)
        {
            crnt += 1;
            result[i].type = COND;
            result[i].cond = JA;
            i++;
        }

        else if(strncmp("<", crnt, 1) == 0)
        {
            crnt += 1;
            result[i].type = COND;
            result[i].cond = JB;
            i++;
        }

        else if(strncmp("if", crnt, 2) == 0)
        {
            crnt += 2;
            result[i].type = CONDOP;
            result[i].condop = IF;
            i++;
        }

        else if (strncmp("else", crnt, 4) == 0)
        {
            crnt += 4;
            result[i].type = CONDOP;
            result[i].condop = ELSE;
            i++;
        }

        else if (strncmp("while", crnt, 5) == 0)
        {
            crnt += 5;
            result[i].type = CYCLE;
            result[i].cycle = WHILE;
            i++;
        }

        else if (strncmp("for", crnt, 3) == 0)
        {
            crnt += 3;
            result[i].type = CYCLE;
            result[i].cycle = FOR;
            i++;
        }

        else if ('0' <= *crnt && *crnt <= '9')
        {
            int val = 0;

            do
            {
                val = val*10 + *crnt - '0';
                crnt++;
            }
            while ('0' <= *crnt && *crnt <= '9');

            result[i].type = NUMBER;
            result[i].number = val;
            i++;
        }

        else if (*crnt == '.')
        {
            result[i].type = DOT;
            i++;
            crnt++;
        }

        else if ((*crnt == '/') && (*(crnt + 1) == '/'))
        {
            crnt++;
            do crnt++;
            while ((*crnt != '\n') || (*crnt != '\0'));
            crnt++;
        }

        else if ((*crnt == '+') || (*crnt == '-') || (*crnt == '*') || (*crnt == '/') || (*crnt == '\'') || (*crnt) == '=')
        {
            result[i].type = OP;
            result[i].op = *crnt;
            crnt++;
            i++;
        }

        else if ((*crnt == ')') || (*crnt == '(') || (*crnt == '}') || (*crnt == '{') || (*crnt == '[') || (*crnt) == ']')
        {
            result[i].type = BR;
            result[i].br = *crnt;
            crnt++;
            i++;
        }

        else if(*crnt == ';')
        {
            result[i].type = EOE;
            i++;
            crnt++;
        }



        else if (isalpha(*crnt))
        {
            result[i].type = VAR;
            result[i].var = *crnt;
            crnt++;
            i++;
        }
        else crnt++;
    }
    result[i].type = EOC;
    return result;
}
